package cn.ghf.user.service.impl;

import cn.ghf.basic.constant.WxConstants;
import cn.ghf.basic.exception.MyException;
import cn.ghf.basic.util.AjaxResult;
import cn.ghf.basic.util.HttpClientUtils;
import cn.ghf.basic.util.MD5Utils;
import cn.ghf.basic.util.StrUtils;
import cn.ghf.user.domain.LoginInfo;
import cn.ghf.user.domain.User;
import cn.ghf.user.domain.WxUser;
import cn.ghf.user.dto.LoginDto;
import cn.ghf.user.mapper.LoginInfoMapper;
import cn.ghf.user.mapper.UserMapper;
import cn.ghf.user.mapper.WxUserMapper;
import cn.ghf.user.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService{

    @Autowired
    private LoginInfoMapper loginInfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private UserMapper userMapper;

    /**
     * 登录
     * @param loginDto
     * @return
     */
    @Override
    public Map<String, Object> acount(LoginDto loginDto) {
        //1.判断非空
        if(StringUtils.isEmpty(loginDto.getUsername())
           || StringUtils.isEmpty(loginDto.getPassword())
           || StringUtils.isEmpty(loginDto.isType()) )
        {
            throw new MyException("请输入完整信息");
        }
        //2.根据用户名和类型判断是否存在
        LoginInfo loginInfo = loginInfoMapper.loadByLoginDot(loginDto);
        if(StringUtils.isEmpty(loginInfo)){
            throw new MyException("用户名错误");
        }
        //3.用户名存在，判断密码是否正确
        //获取当前用户的盐值
        String salt = loginInfo.getSalt();
        String password = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);
        //获取数据库中的密码
        String dbpassword = loginInfo.getPassword();
        if(!password.equals(dbpassword)){
            throw new MyException("密码错误");
        }
        //4.用户和密码都正确，把用户信息放入redis
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token,loginInfo ,30 , TimeUnit.MINUTES );
        Map<String,Object> map = new HashMap<>();
        map.put("token",token );

        //把密码和盐值设为空
        loginInfo.setPassword("");
        loginInfo.setSalt("");
        map.put("loginInfo", loginInfo);
        return map;
    }

    /**
     * 微信登录
     * @param map
     * @return
     */
    @Override
    public AjaxResult wechat(Map<String, String> map) {
        //1.code为空
        String code = map.get("code");
        if(StringUtils.isEmpty(code)){
            throw new MyException("系统异常");
        }
        //通过APPID SECRET code获取token
        String url = WxConstants.GET_TOKEN_URL.replace("APPID", WxConstants.APPID)
                .replace("SECRET",WxConstants.SECRET )
                .replace("CODE",code );
        String obj = HttpClientUtils.httpGet(url);
        //把obj对象转成json格式
        JSONObject jsonObject = JSONObject.parseObject(obj);
        //System.out.println(jsonObject);
        //获取access_token openid
        String access_token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        System.out.println(openid+"===");

        //通过openid 和userid查询，如果不为空，说明登录过，免密登录
        WxUser wxUser = wxUserMapper.loadByOpenId(openid);
        String param = "?access_token="+access_token+"&openid="+openid;
        if(wxUser!=null && wxUser.getUser_id()!=null){  //将用户信息存到redis中
            //查询loginInfo信息
            LoginInfo loginInfo = loginInfoMapper.loadByUserId(wxUser.getUser_id());

            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token,loginInfo ,30 , TimeUnit.MINUTES );
            Map<String,Object> wxmap = new HashMap<>();
            wxmap.put("token",token );

            //把密码和盐值设为空
            loginInfo.setPassword("");
            loginInfo.setSalt("");
            wxmap.put("loginInfo", loginInfo);

            return AjaxResult.createAjaxResult().setResultObj(wxmap);
        }
        //第一次登录，跳转到绑定界面
        return AjaxResult.createAjaxResult().setSuccess(false).setResultObj(param);
    }

    /**
     * 微信绑定手机号
     * @param map
     * @return
     */
    @Override
    public Map<String, Object> binder(Map<String, String> map) {
        String verifyCode = map.get("verifyCode");
        String accessToken = map.get("accessToken");
        String openId = map.get("openId");
        String phone = map.get("phone");

        //1.手机号非空校验
        if(StringUtils.isEmpty(phone)){
            throw new MyException("手机号不能为空");
        }
        //2.验证码校验,是否失效
        Object o = redisTemplate.opsForValue().get("binder:" + phone);
        if(o==null){
            throw new MyException("验证码已失效，请重新获取");
        }
        //验证码是否正确
        String code = o.toString().split(":")[0];
        if(!verifyCode.equalsIgnoreCase(code)){
            throw new MyException("验证码错误，请重新输入");
        }
        //3.判断手机号是否注册
        User user = userMapper.loadByPhone(phone);
        User userTemp = null;
        LoginInfo loginInfo = null;
        if(user != null){  //当前手机号注册过
            userTemp=user;
            loginInfo = loginInfoMapper.loadByUserId(userTemp.getId());
        }else{ //当前手机号没注册过，保存三张表，user logininfo wxuser
            userTemp = initUser(phone);
            loginInfo = initLoginInfo(userTemp);
            loginInfo.setType(true);
            //把user和logininfo保存
            loginInfoMapper.add(loginInfo);
            userTemp.setLogininfo_id(loginInfo.getId());
            userMapper.add(userTemp);
        }
        //获取用户信息，保存在wxuser中
        //https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
        String obj = HttpClientUtils.httpGet(WxConstants.GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId));
        WxUser wxUser = initWxUser(obj);
        //绑定
        wxUser.setUser_id(userTemp.getId());
        //保存wxuser中的信息
        wxUserMapper.add(wxUser);

        //把用户信息存在redis中
        //4.用户和密码都正确，把用户信息放入redis
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token,loginInfo ,30 , TimeUnit.MINUTES );
        Map<String,Object> map2 = new HashMap<>();
        map2.put("token",token );

        //把密码和盐值设为空
        loginInfo.setPassword("");
        loginInfo.setSalt("");
        map2.put("loginInfo", loginInfo);
        return map2;

    }

    /**
     * 根据obj生成wxuser对象
     * @param obj
     * @return
     */
    private WxUser initWxUser(String obj) {
        JSONObject jsonObject = JSONObject.parseObject(obj);
        WxUser wxUser = new WxUser();
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }

    /**
     * 根据user对象生成logininfo对象
     * @param userTemp
     * @return
     */
    private LoginInfo initLoginInfo(User userTemp) {
        LoginInfo info = new LoginInfo();
        BeanUtils.copyProperties(userTemp,info); //按照同名原则拷贝属性
        return info;
    }

    /**
     * 根据手机号生成user对象
     * @param phone
     * @return
     */
    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        user.setEmail(null);
        //给一个随机密码
        String salt = UUID.randomUUID().toString();
        String password = MD5Utils.encrypByMd5("1"+salt);
        user.setPassword(password);
        user.setSalt(salt);
        user.setState(1);
        user.setCreatetime(new Date());
        return user;
    }
}
